//
// Created by yxyx on 2021-11-22.
//

#ifndef SFML_DEMO_UTILS_HPP
#define SFML_DEMO_UTILS_HPP

#include <time.h>
#include <string>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <sstream>
#include <random>
#include "matrix.hpp"
using namespace std;

string get_now_time_str();

long long time_ms();

Matrix<double> *padding(Matrix<double> *src, int pad, int dim);

string get_now_time_str(){
    struct tm *newtime;
    char tmpbuf[128];
    time_t t;
    time(&t);
    newtime = localtime(&t);
    strftime(tmpbuf, 128, "%A, day %d of %B year %Y./n", newtime);
    return string(tmpbuf);
}


long long time_ms() {
    return std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::system_clock::now().time_since_epoch()).count();
}

void free_data(std::vector<std::vector<Matrix<double> *>> *data) {
    for (int i = 0; i < data->size(); ++i) {
        for (int j = 0; j < (*data)[i].size(); ++j) {
            delete ((*data)[i][j]);
        }
    }
    delete (data);
}












/**
 *
 * @param src
 * @param pad
 * @param dim 0是行和列, 1是对每一行pad, 2是对每一列pad
 * @return
 */
Matrix<double> *padding(Matrix<double> *src, int pad, int dim) {
    int width = 0;
    int height = 0;
    Matrix<double> *pad_mat = nullptr;
    switch (dim) {
        case 0:
            width = src->width + (2 * pad);
            height = src->height + (2 * pad);
            pad_mat = new Matrix<double>(height, width);
            for (int i = 0; i < height; ++i) {
                for (int j = 0; j < width; ++j) {
                    if (i >= pad && i < height - pad && j >= pad && j < width - pad) {
                        pad_mat->set(i, j, src->get(i - pad, j - pad));
                    }
                }
            }
            break;
        case 1:
            width = src->width + (2 * pad);
            height = src->height;
            pad_mat = new Matrix<double>(height, width);
            for (int i = 0; i < height; ++i) {
                for (int j = 0; j < width; ++j) {
                    if (j >= pad && j < width - pad) {
                        pad_mat->set(i, j, src->get(i, j - pad));
                    }
                }
            }
            break;
        case 2:
            width = src->width;
            height = src->height + (2 * pad);
            pad_mat = new Matrix<double>(height, width);
            for (int i = 0; i < height; ++i) {
                for (int j = 0; j < width; ++j) {
                    if (i >= pad && i < height - pad) {
                        pad_mat->set(i, j, src->get(i - pad, j));
                    }
                }
            }
            break;
    }

    return pad_mat;
}








/**
 * 单张图片的还原
 * @param col 需要变形回去的矩阵
 * @param src_w 原始矩阵宽度
 * @param src_h 原始矩阵高度
 * @param filter_size 卷积核边长
 * @param stride 卷积滑动步长
 * @return
 */
Matrix<double> *col2im(Matrix<double> *col, int src_w, int src_h, int filter_h, int filter_w, int stride) {
    auto origin = new Matrix<double>(src_h, src_w);
    auto mask = new Matrix<double>(src_h, src_w);
    int num_row = 0; //col矩阵的第几行
    Matrix<double> *row = nullptr;
    for (int i = 0; i <= origin->height - filter_h; i += stride) {
//        num_row = 0;
        for (int j = 0; j <= origin->width - filter_w; j += stride) {
            row = col->row(num_row++);
            int idx = 0;
            for (int m = i; m < i + filter_h; ++m) {
                for (int n = j; n < j + filter_w; ++n) {
                    if (origin->get(m, n) == 0) {
                        origin->set(m, n, row->get(0, idx++));
                    } else {
                        idx++;
                    }
                }
            }
            delete (row);
        }
    }
    delete (mask);
    return origin;
}




#endif //SFML_DEMO_UTILS_HPP
